﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace TileEngine
{
    public class TileLayer
    {
        static int tileWidth = 64;
        static int tileHeight = 64;

        public static int TileWidth
        {
            get { return tileWidth; }
            set { tileWidth = (int)MathHelper.Clamp(value, 20f, 100f); }
        }

        public static int TileHeight
        {
            get { return tileHeight; }
            set { tileHeight = (int)MathHelper.Clamp(value, 20f, 100f); }
        }

        
        List<Texture2D> tileTextures = new List<Texture2D>();
        int[,] map;
        float alpha = 1f;

        public float Alpha
        {
            get { return alpha; }
            set { alpha = MathHelper.Clamp(value, 0f, 1f); }
        }


        public int WidthInPixels{get { return Width * tileWidth; }}
        public int HeightInPixels{get { return Height * tileHeight;}}

        public int Width { get { return map.GetLength(1); } }
        public int Height { get { return map.GetLength(0); } }

        public TileLayer(int width, int height)
        {
            map = new int[height, width];

            for (int x = 0; x < width; x++)
                for (int y = 0; y < height; y++)
                    map[y, x] = -1;
        }

        public TileLayer(int[,] existingMap)
        {
                map = (int[,])existingMap.Clone();
        }


        public int IsUsingTexture(Texture2D texture)
        {
            if ( tileTextures.Contains(texture))
                return tileTextures.IndexOf(texture);
            else
                return -1;
        }


        public void SaveLayerToFile(string filename, string[] textureNames)
        {
            using (StreamWriter writer = new StreamWriter(filename))
            {
                writer.WriteLine("[Texture]");
                foreach (string t in textureNames)
                    writer.WriteLine(t);

                writer.WriteLine();

                writer.WriteLine("[Layout]");

                for (int y = 0; y < Height; y++)
                {

                    string line = string.Empty;
                    for (int x = 0; x < Width; x++)
                    {
                        line += map[y, x].ToString() + " ";
                    }

                    writer.WriteLine(line);
                }
            }
        }




        public static TileLayer FromFile(ContentManager content, string filename)
        { 
           TileLayer tileLayer;
           bool readingTextures = false;
           bool readingLayout = false;
           List<string> textureNames = new List<string>();
           List<List<int>> tempLayout = new List<List<int>>();
           

           using (StreamReader reader = new StreamReader(filename))
           {
               while (!reader.EndOfStream) 
               {
                   string line = reader.ReadLine().Trim();

                   if (string.IsNullOrEmpty(line))
                       continue;
                   if (line.Contains("[Texture]"))
                   {
                       readingTextures = true;
                       readingLayout = false;

                   }
                   else if (line.Contains("[Layout]"))
                   {
                       readingLayout = true;
                       readingTextures = false;                  
                   }

                   else if (readingTextures)
                   {
                       textureNames.Add(line);
                   }

                   else if (readingLayout)
                   {
                       List<int> row = new List<int>();

                       string[] cells = line.Split(' ');

                       foreach (string c in cells)
                       {
                           if (!string.IsNullOrEmpty(c))
                               row.Add(int.Parse(c));
                       }

                       tempLayout.Add(row);
                   }
               }
           }

           int width = tempLayout[0].Count;
           int height = tempLayout.Count;

           tileLayer = new TileLayer(width, height);

           for (int y = 0; y < height; y++)
               for (int x = 0; x < width; x++)
                   tileLayer.SetCellIndex(x, y, tempLayout[y][x]);

           tileLayer.LoadTileTexture(content, textureNames.ToArray());

           return tileLayer;
        }

        public static TileLayer FromFile(string filename, out string[] textureNameArray)
        {
            TileLayer tileLayer;
            bool readingTextures = false;
            bool readingLayout = false;
            List<string> textureNames = new List<string>();
            List<List<int>> tempLayout = new List<List<int>>();


            using (StreamReader reader = new StreamReader(filename))
            {
                while (!reader.EndOfStream)
                {
                    string line = reader.ReadLine().Trim();

                    if (string.IsNullOrEmpty(line))
                        continue;
                    if (line.Contains("[Texture]"))
                    {
                        readingTextures = true;
                        readingLayout = false;

                    }
                    else if (line.Contains("[Layout]"))
                    {
                        readingLayout = true;
                        readingTextures = false;
                    }

                    else if (readingTextures)
                    {
                        textureNames.Add(line);
                    }

                    else if (readingLayout)
                    {
                        List<int> row = new List<int>();

                        string[] cells = line.Split(' ');

                        foreach (string c in cells)
                        {
                            if (!string.IsNullOrEmpty(c))
                                row.Add(int.Parse(c));
                        }

                        tempLayout.Add(row);
                    }
                }
            }

            int width = tempLayout[0].Count;
            int height = tempLayout.Count;

            tileLayer = new TileLayer(width, height);

            for (int y = 0; y < height; y++)
                for (int x = 0; x < width; x++)
                    tileLayer.SetCellIndex(x, y, tempLayout[y][x]);

            textureNameArray = textureNames.ToArray();

            return tileLayer;
        }


        public void LoadTileTexture(ContentManager content, params string[] textureNames)
        {
            Texture2D texture;

            foreach (string textureName in textureNames)
            {
                texture = content.Load<Texture2D>(textureName);
                tileTextures.Add(texture);
            }

        }

        


        public void AddTexture(Texture2D texture)
        {
            tileTextures.Add(texture);
        }
        
        public void SetCellIndex(int x, int y, int cellIndex)
        {
            map[y, x] = cellIndex;
        }

        public int GetCellIndex(int x, int y)
        {
            return map[y, x];
        }

        public void Draw(SpriteBatch batch, Camera camera)
        {
            batch.Begin(SpriteSortMode.Immediate,BlendState.AlphaBlend);

            int tileMapWidth = map.GetLength(1);
            int tileMapHight = map.GetLength(0);

            for (int x = 0; x < tileMapWidth; x++)
            {
                for (int y = 0; y < tileMapHight; y++)
                {
                    int textureIndex = map[y, x];

                    if (textureIndex == -1)
                        continue;

                    else
                    {
                        Texture2D texture = tileTextures[textureIndex];

                        batch.Draw(
                            texture,
                            new Rectangle(
                                x * tileWidth - (int)camera.Position.X,
                                y * tileHeight - (int)camera.Position.Y,
                                tileWidth,
                                tileHeight),
                            new Color(new Vector4(1f,1f,1f, Alpha)));
                    }
                }
            }

            batch.End();
   
        }

    }
}
